﻿namespace eeenno.SpeeedReaderUI.NativeWebBrowser.Windows.Forms
{
    using Microsoft.WindowsCE.Forms;
    using eeenno.SpeeedReaderUI.NativeWebBrowser.Runtime.InteropServices;
    using eeenno.SpeeedReaderUI.NativeWebBrowser.Win32;
    using eeenno.ReaderEngine.Utilities;
    using System;
    using System.Collections;
    using System.Drawing;
    using System.Runtime.CompilerServices;
    using System.Runtime.InteropServices;
    using System.Diagnostics;

    public class WebBrowser : ControlEx
    {
        private bool is_busy;        
        private bool m_addtohistory;
        private bool m_cleartype;
        private bool m_contextmenu;
        private Stack m_history;
        private bool m_script;
        private bool m_shrink;
        private string m_title;
        private string m_url;

        public event WebBrowserDocumentCompletedEventHandler DocumentCompleted;

        public event EventHandler DocumentTitleChanged;

        public event WebBrowserNavigatedEventHandler Navigated;

        public event WebBrowserNavigatingEventHandler Navigating;

        static WebBrowser()
        {
            Core.LoadLibrary("htmlview.dll");
            InitHTMLControl(ControlEx.Instance);
        }

        public WebBrowser() : base(true)
        {
            this.is_busy = false;
            this.m_script = true;
            this.m_shrink = true;
            this.m_addtohistory = false;
            this.m_history = new Stack();
        }

        public void AddText(string text)
        {
            this.AddText(text, false);
        }

        public void AddText(string text, bool plain)
        {
            IntPtr hGlobal = MarshalEx.StringToHGlobalUni(text + '\0');
            int wParam = 0;
            if (plain)
            {
                wParam = -1;
            }
            Win32Window.SendMessage(base.ChildHandle, 0x466, wParam, (int) hGlobal);
            MarshalEx.FreeHGlobal(hGlobal);
        }

        public void Clear()
        {
            this.Text = "";
            Win32Window.SendMessage(base.ChildHandle, 0x471, 0, 0);
        }

        public void EndOfSource()
        {
            Win32Window.SendMessage(base.ChildHandle, 0x468, 0, 0);
        }

        public void GoBack()
        {
            if (this.m_history.Count > 0)
            {
                this.m_addtohistory = false;
                this.Navigate(this.m_history.Pop().ToString());
            }
        }

        public void GoHome()
        {
            this.Navigate("about:home");
        }

        [DllImport("htmlview.dll", SetLastError=true)]
        private static extern int InitHTMLControl(IntPtr hinst);
        public void JumpToAnchor(string anchor)
        {
            IntPtr hGlobal = MarshalEx.StringToHGlobalUni(anchor + '\0');
            Win32Window.SendMessage(base.ChildHandle, 0x46a, 0, (int) hGlobal);
            MarshalEx.FreeHGlobal(hGlobal);
        }

        public void Navigate(string url)
        {
            if (!is_busy)
            {
                is_busy = true;
                IntPtr hGlobal = MarshalEx.StringToHGlobalUni(url + '\0');
                if (base.ChildHandle != IntPtr.Zero)
                {
                    Win32Window.SendMessage(base.ChildHandle, 0x478, 0x1000, (int)hGlobal);
                }
                MarshalEx.FreeHGlobal(hGlobal);
                is_busy = false;
            }
        }

        protected virtual void OnDocumentCompleted(WebBrowserDocumentCompletedEventArgs e)
        {
            if (this.DocumentCompleted != null)
            {
                this.DocumentCompleted(this, e);
            }
        }

        protected virtual void OnDocumentTitleChanged(EventArgs e)
        {
            if (this.DocumentTitleChanged != null)
            {
                this.DocumentTitleChanged(this, e);
            }
        }

        protected override void OnGotFocus(EventArgs e)
        {
            Win32Window.SetFocus(Win32Window.GetWindow(base.ChildHandle, GW.CHILD));
        }

        protected virtual void OnNavigated(WebBrowserNavigatedEventArgs e)
        {
            if ((this.m_url != null) & this.m_addtohistory)
            {
                this.m_history.Push(this.m_url);
                this.m_addtohistory = true;
            }
            this.m_url = e.Url;
            if (this.Navigated != null)
            {
                this.Navigated(this, e);
            }
        }

        protected virtual void OnNavigating(WebBrowserNavigatingEventArgs e)
        {
            if (!is_busy && this.Navigating != null)
            {
                this.Navigating(this, e);
            }
        }

        protected override void OnNotifyMessage(ref Microsoft.WindowsCE.Forms.Message m)
        {
            if (m.Msg == 0x4e)
            {
                NMHDR nmhdr = (NMHDR) Marshal.PtrToStructure(m.LParam, typeof(NMHDR));
                if (nmhdr.code == 0x46b)
                {
                    if (this.ContextMenu != null)
                    {
                        NM_HTMLCONTEXT nm_htmlcontext = (NM_HTMLCONTEXT) Marshal.PtrToStructure(m.LParam, typeof(NM_HTMLCONTEXT));
                        m.Result = new IntPtr(-1);
                        Point point = new Point(nm_htmlcontext.x, nm_htmlcontext.y);
                        this.ContextMenu.Show(this, point);
                    }
                }
                else
                {
                    NM_HTMLVIEW nm_htmlview = (NM_HTMLVIEW) Marshal.PtrToStructure(m.LParam, typeof(NM_HTMLVIEW));
                    string url = MarshalEx.PtrToStringAuto(nm_htmlview.szTarget);
                    switch (nm_htmlview.code)
                    {
                        case 0x468:
                        case 0x470:
                            this.m_title = url;
                            this.OnDocumentTitleChanged(new EventArgs());
                            goto Label_0149;

                        case 0x469:
                        case 0x46a:
                        case 0x46b:
                        case 0x46c:
                            goto Label_0149;

                        case 0x46d:
                        case 0x465:
                            this.OnNavigating(new WebBrowserNavigatingEventArgs(url));
                            /*if (!Settings.always_use_internal_browser)
                            {
                                Process.Start(url, String.Empty);
                                m.Result = new IntPtr(-1);
                            }*/
                            //if(Settings.always_use_internal_browser)
                            //{
                            //    Navigate(url);
                            //}
                            m.Result = new IntPtr(-1);
                            goto Label_0149;

                        case 0x46e:
                            this.OnDocumentCompleted(new WebBrowserDocumentCompletedEventArgs(url));
                            goto Label_0149;

                        case 0x46f:
                            this.OnNavigated(new WebBrowserNavigatedEventArgs(url));
                            goto Label_0149;
                    }
                }
            }
        Label_0149:
            base.OnNotifyMessage(ref m);
        }

        public override void Refresh()
        {
            if (this.m_url != null)
            {
                IntPtr hGlobal = MarshalEx.StringToHGlobalUni(this.m_url + '\0');
                Win32Window.SendMessage(base.ChildHandle, 0x478, 0x20, (int) hGlobal);
                MarshalEx.FreeHGlobal(hGlobal);
            }
        }

        public void SelectAll()
        {
            Win32Window.SendMessage(base.ChildHandle, 0x46f, 0, 0);
        }

        public void Stop()
        {
            Win32Window.SendMessage(base.ChildHandle, 0x47d, 0, 0);
        }

        public bool CanGoBack
        {
            get
            {
                if (this.m_history.Count <= 0)
                {
                    return false;
                }
                return true;
            }
        }

        protected override eeenno.SpeeedReaderUI.NativeWebBrowser.Windows.Forms.CreateParams CreateParams
        {
            get
            {
                eeenno.SpeeedReaderUI.NativeWebBrowser.Windows.Forms.CreateParams createParams = base.CreateParams;
                createParams.ClassStyle = (createParams.ClassStyle | 4) | 0x200;
                createParams.ClassName = "DISPLAYCLASS";
                return createParams;
            }
        }

        public string DocumentText
        {
            set
            {
                this.AddText(value);
                this.EndOfSource();
            }
        }

        public string DocumentTitle
        {
            get
            {
                return this.m_title;
            }
        }

        public bool EnableClearType
        {
            get
            {
                return this.m_cleartype;
            }
            set
            {
                this.m_cleartype = value;
                if (base.Created)
                {
                    int lParam = value ? -1 : 0;
                    Win32Window.SendMessage(base.ChildHandle, 0x472, 0, lParam);
                }
                if (value)
                {
                    this.CreateParams.ClassStyle |= 4;
                }
                else
                {
                    this.CreateParams.ClassStyle ^= 4;
                }
            }
        }

        public bool EnableContextMenu
        {
            get
            {
                return this.m_contextmenu;
            }
            set
            {
                this.m_contextmenu = value;
                if (base.Created)
                {
                    int lParam = value ? -1 : 0;
                    Win32Window.SendMessage(base.ChildHandle, 0x46e, 0, lParam);
                }
                if (value)
                {
                    this.CreateParams.ClassStyle |= 2;
                }
                else
                {
                    this.CreateParams.ClassStyle ^= 2;
                }
            }
        }

        public bool EnableScripting
        {
            get
            {
                return this.m_script;
            }
            set
            {
                this.m_script = value;
                if (base.Created)
                {
                    int lParam = value ? -1 : 0;
                    Win32Window.SendMessage(base.ChildHandle, 0x473, 0, lParam);
                }
                if (value)
                {
                    this.CreateParams.ClassStyle ^= 8;
                }
                else
                {
                    this.CreateParams.ClassStyle |= 8;
                }
            }
        }

        public bool EnableShrink
        {
            get
            {
                return this.m_shrink;
            }
            set
            {
                this.m_shrink = value;
                if (base.Created)
                {
                    int lParam = value ? -1 : 0;
                    Win32Window.SendMessage(base.ChildHandle, 0x46b, 0, lParam);
                }
                if (value)
                {
                    this.CreateParams.ClassStyle |= 1;
                }
                else
                {
                    this.CreateParams.ClassStyle ^= 1;
                }
            }
        }

        public bool IsBusy
        {
            get { return is_busy; }
        }

        public int LayoutHeight
        {
            get
            {
                return (int) Win32Window.SendMessage(base.ChildHandle, 0x476, 0, 0);
            }
        }

        public int LayoutWidth
        {
            get
            {
                return (int) Win32Window.SendMessage(base.ChildHandle, 0x475, 0, 0);
            }
        }

        public string Url
        {
            get
            {
                return this.m_url;
            }
            set
            {
                this.m_url = value;
                this.Navigate(this.m_url);
            }
        }

        private enum DTM
        {
            ADDSTYLE = 0x47e,
            ADDTEXT = 0x465,
            ADDTEXTW = 0x466,
            ANCHOR = 0x469,
            ANCHORW = 0x46a,
            BROWSERDISPATCH = 0x47c,
            CLEAR = 0x471,
            ENABLECLEARTYPE = 0x472,
            ENABLECONTEXTMENU = 0x46e,
            ENABLESCRIPTING = 0x473,
            ENABLESHRINK = 0x46b,
            ENDOFSOURCE = 0x468,
            IMAGEFAIL = 0x46d,
            ISSELECTION = 0x470,
            LAYOUTHEIGHT = 0x476,
            LAYOUTWIDTH = 0x475,
            NAVIGATE = 0x478,
            SELECTALL = 0x46f,
            SETIMAGE = 0x467,
            STOP = 0x47d,
            WM_GETTEXT = 13,
            WM_GETTEXTLENGTH = 14,
            WM_SETTEXT = 12,
            WM_USER = 0x400,
            ZOOMLEVEL = 0x474
        }

        [Flags]
        private enum NAVIGATEFLAG
        {
            ENTERED = 0x80,
            GETFROMCACHE = 0x400,
            IGNORETARGET = 0x200,
            NOCACHE = 0x1000,
            REFRESH = 0x20,
            RELATIVE = 0x40,
            RESYNCHRONIZE = 0x2000
        }

        private enum NM
        {
            BASE = 0x46a,
            BEFORENAVIGATE = 0x46d,
            CONTEXTMENU = 0x46b,
            DOCUMENTCOMPLETE = 0x46e,
            HOTSPOT = 0x465,
            INLINE_IMAGE = 0x466,
            INLINE_SOUND = 0x467,
            INLINESTYLE = 0x471,
            INLINEXML = 0x46c,
            META = 0x469,
            NAVIGATECOMPLETE = 0x46f,
            TITLE = 0x468,
            TITLECHANGE = 0x470,
            WM_USER = 0x400
        }

        [StructLayout(LayoutKind.Sequential)]
        private struct NM_HTMLCONTEXT
        {
            public IntPtr hwndFrom;
            public int idFrom;
            public int code;
            public int x;
            public int y;
            public uint uTypeFlags;
            public IntPtr szLinkHREF;
            public IntPtr szLinkName;
            private int dwUnused;
            public int dwImageCooki;
            private int dwUnused2;
        }

        [StructLayout(LayoutKind.Sequential)]
        private struct NM_HTMLVIEW
        {
            public IntPtr hwndFrom;
            public int idFrom;
            public int code;
            public IntPtr szTarget;
            public IntPtr szData;
            public IntPtr dwCookie;
            public IntPtr szExInfo;
        }
    }
}

